package avicit.bdp.dcs.job.service;

import avicit.bdp.common.base.BaseService;
import avicit.bdp.common.utils.CheckParaUtils;
import avicit.bdp.common.utils.enums.JobType;
import avicit.bdp.core.util.json.JSONUtils;
import avicit.bdp.dcs.datasource.service.BaseDbService;
import avicit.bdp.dcs.datasource.service.TableService;
import avicit.bdp.dcs.job.dao.DcsJobDao;
import avicit.bdp.dcs.job.dto.JobDTO;
import avicit.bdp.dcs.precheck.service.PrecheckService;
import avicit.bdp.dcs.task.dto.TableMappingDto;
import avicit.bdp.dcs.task.service.TaskService;
import avicit.bdp.dcs.tools.enums.ProcessMode;
import avicit.platform6.core.exception.BusinessException;
import org.apache.commons.collections4.CollectionUtils;
import org.datanucleus.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @金航数码科技有限责任公司
 * @作者：liyb
 * @邮箱：liyb@avic-digital.com
 * @创建时间： 2020-11-10 18:53
 * @类说明： 结构化作业服务类
 * @修改记录：
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class StructureJobService extends BaseService<DcsJobDao, JobDTO> implements JobInterface {

    private static final Logger logger = LoggerFactory.getLogger(StructureJobService.class);

    private static final int MAX_JOB_TABLE_NUM = 200;

    @Autowired
    private TaskService taskService;
    @Autowired
    private PrecheckService precheckService;
    @Autowired
    private BaseDbService baseDbService;
    @Autowired
    private TableService tableService;

    /**
     * 作业配置第二步(保存表映射关系)
     * @throws Exception
     */
    @Override
    public void saveTableMapping(JobDTO oldJobDTO, JobDTO newJobDTO) throws Exception {
        // 验证数据
        checkData(newJobDTO);

        // 验证源数据源和目标数据源相同，且表也相同的情况
        checkSrcAndDstDatasource(oldJobDTO, newJobDTO);

        // 验证数据迁移只选择“数据迁移”，但目标表不存在的情况
        checkTransfer(oldJobDTO, newJobDTO);

        // 验证已选择的表<=200(单个作业不超过200张表)
        checkTableNum(newJobDTO);

        if (oldJobDTO.getJobType() == JobType.SYNC.getCode()) {
            newJobDTO.setTransferType(null);
        }

        // 更新Job信息
        this.updateByPrimaryKeySelective(newJobDTO);

        // 批量新增或修改任务
        taskService.saveTasksByJob(oldJobDTO.getId());

        // 新增预检查信息(先删除再新增)
        precheckService.saveJobPrecheck(oldJobDTO.getId());
    }

    /**
     * 验证数据
     */
    private void checkData(JobDTO newJobDTO){
        CheckParaUtils.checkStringValidity(newJobDTO.getTransferType(), logger, "迁移类型必填");
        CheckParaUtils.checkObjectValidity(newJobDTO.getProcessMode(), logger, "已存在表的处理模式必填");
        CheckParaUtils.checkStringValidity(newJobDTO.getSelectedTable(), logger, "待迁移、同步表必填");

        List<TableMappingDto> tableMappingDtoList = JSONUtils.toList(newJobDTO.getSelectedTable(), TableMappingDto.class);
        if (CollectionUtils.isNotEmpty(tableMappingDtoList)) {
            for (TableMappingDto tableMappingDto : tableMappingDtoList) {
                if(StringUtils.isEmpty(tableMappingDto.getDst_table())){
                    throw new BusinessException("目标表必填");
                }
            }
        }
    }

    /**
     * 验证源数据源和目标数据源相同，且表也相同的情况
     * @param oldJobDTO
     * @param newJobDTO
     */
    private void checkSrcAndDstDatasource(JobDTO oldJobDTO, JobDTO newJobDTO){
        if (oldJobDTO.getSrcDatasourceId().equals(oldJobDTO.getDstDatasourceId())) {
            List<TableMappingDto> tableMappingDtoList = JSONUtils.toList(newJobDTO.getSelectedTable(), TableMappingDto.class);
            if (CollectionUtils.isNotEmpty(tableMappingDtoList)) {
                for (TableMappingDto tableMappingDto : tableMappingDtoList) {
                    if (tableMappingDto.getSrc_table().equals(tableMappingDto.getDst_table())) {
                        throw new BusinessException(String.format("同一个数据源中,源表%s和目标表%s不能相同",
                                tableMappingDto.getSrc_table(), tableMappingDto.getDst_table()));
                    }
                }
            }
        }
    }

    /**
     * 验证数据迁移只选择“数据迁移”，但目标表不存在的情况
     * @param oldJobDTO
     * @param newJobDTO
     * @throws Exception
     */
    private void checkTransfer(JobDTO oldJobDTO, JobDTO newJobDTO) throws Exception {
        if (oldJobDTO.getJobType() == JobType.TRANSFER.getCode() && newJobDTO.getProcessMode() != null
                && newJobDTO.getProcessMode() == ProcessMode.RETAIN_DST_TABLE.getCode()) {

            List<String> tableList = baseDbService.getTableList(oldJobDTO.getDstDatasourceId());
            tableList.stream().map(String::toLowerCase);

            List<TableMappingDto> tableMappingDtoList = JSONUtils.toList(newJobDTO.getSelectedTable(), TableMappingDto.class);
            if (CollectionUtils.isNotEmpty(tableMappingDtoList) && CollectionUtils.isNotEmpty(tableList)) {
                for (TableMappingDto tableMappingDto : tableMappingDtoList) {
                    if (!tableList.contains(tableMappingDto.getDst_table().toLowerCase())) {
                        throw new BusinessException(String.format("你选择仅数据迁移，但目标库中不存在表:%s，请重新选择表",
                                tableMappingDto.getDst_table()));
                    }
                }
            }
        }
    }

    /**
     * 验证已选择的表<=200(单个作业不超过200张表)
     * @param newJobDTO
     * @throws Exception
     */
    private void checkTableNum(JobDTO newJobDTO) throws Exception {
        List<TableMappingDto> tableMappingDtoList = JSONUtils.toList(newJobDTO.getSelectedTable(), TableMappingDto.class);
        if (CollectionUtils.isNotEmpty(tableMappingDtoList) && tableMappingDtoList.size() > MAX_JOB_TABLE_NUM) {
            throw new BusinessException("单个作业不超过200张表");
        }
    }

}
